package com.geek.gkfgw.biz.controller.auth.login;

import com.geek.gkfgw.biz.redis.RecvTokenInfoRedisListener;
import com.geek.gkfgw.facade.auth.login.LoginByAccountPwdRequest;
import com.geek.gkfgw.facade.auth.login.LoginByAccountPwdResponse;
import com.geek.gkfgw.framework.cache.util.EhcacheUtils;
import com.geek.gkfgw.framework.cache.util.RedisUtils;
import com.geek.gkfgw.service.token.bean.TokenInfo;
import com.geek.gkfgw.util.consts.SystemConsts;
import com.geek.gkfgw.util.excp.GkFgwCodeEnum;
import com.geek.gkfgw.util.excp.GkFgwException;
import com.geek.gkmember.facade.login.LoginFacade;
import com.geek.gkmember.facade.login.bean.LoginByAccountPwdReq;
import com.geek.gkmember.facade.login.bean.LoginByAccountPwdResp;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * <h1>通过账号+密码登录处理类。</h1>
 *
 * <h1><br/><a href="https://u.geekbang.org/subject/arch3/100614201">Java 业务架构实战营：https://u.geekbang.org/subject/arch3/100614201</a></h1><br/><h1><a href="https://gitee.com/ylimhhmily/BizArchPracticeCamp">Java 业务架构实战营代码地址：https://gitee.com/ylimhhmily/BizArchPracticeCamp</a></h1><br/><h1><a href="https://u.geekbang.org/subject/java4th/1001148?source=app_share">高级 Java 工程体系课 2023 版：https://u.geekbang.org/subject/java4th/1001148?source=app_share</a></h1><br/><h1><a href="https://time.geekbang.org/column/intro/100312101?tab=catalog">Dubbo 源码剖析与实战：https://time.geekbang.org/column/intro/100312101?tab=catalog</a></h1>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2023/10/15 17:24
 */
@Component
public class LoginByAccountPwdAction {

    @DubboReference
    private LoginFacade loginFacade;

    /**
     * <h2>通过账号+密码登录。</h2>
     *
     * @param: req
     * @return: com.geek.gkfgw.facade.auth.login.LoginByAccountPwdResponse
     */
    public LoginByAccountPwdResponse loginByAccountPwd(LoginByAccountPwdRequest req) {
        // 组装请求数据
        LoginByAccountPwdReq remoteReq = buildRemoteLoginByAccountPwdReq(req);

        // 远程调用
        LoginByAccountPwdResp remoteResp = doLoginByAccountPwd(remoteReq);

        // 写缓存
        save2Cache(remoteResp);

        // 组装返回数据
        return buildSuccResp(remoteResp);
    }

    private void save2Cache(LoginByAccountPwdResp remoteResp) {
        String accessToken = remoteResp.getAccessToken();

        TokenInfo tokenInfo = new TokenInfo();
        tokenInfo.setExpireTimeMillis(remoteResp.getExpireTimeMillis());
        tokenInfo.setUserId(remoteResp.getUserId());
        tokenInfo.setUserName(remoteResp.getUserName());

        // TODO 这里就先暂时省略了定长+变成的赋值了
        String cackeKey = RecvTokenInfoRedisListener.CACHE_TOKEN_PREFIX + accessToken;
        RedisUtils.set(cackeKey, tokenInfo, 1, TimeUnit.MINUTES);
    }

    private LoginByAccountPwdResp doLoginByAccountPwd(LoginByAccountPwdReq remoteReq) {
        LoginByAccountPwdResp remoteResp = loginFacade.loginByAccountPwd(remoteReq);

        // 解析响应
        if (remoteResp == null) {
            throw new GkFgwException(GkFgwCodeEnum.INVOKE_INTEGRATION_EXCEPTION);
        }
        if (GkFgwCodeEnum.isFail(remoteResp.getRespCode())) {
            throw new GkFgwException(remoteResp.getRespCode(), remoteResp.getRespMsg());
        }

        return remoteResp;
    }

    private LoginByAccountPwdResponse buildSuccResp(LoginByAccountPwdResp remoteResp) {
        LoginByAccountPwdResponse response = new LoginByAccountPwdResponse();

        response.setRefreshToken(remoteResp.getRefreshToken());
        response.setAccessToken(remoteResp.getAccessToken());
        response.setExpireTimeMillis(remoteResp.getExpireTimeMillis());

        return response;
    }

    private LoginByAccountPwdReq buildRemoteLoginByAccountPwdReq(LoginByAccountPwdRequest req) {
        LoginByAccountPwdReq remoteReq = new LoginByAccountPwdReq();

        remoteReq.setFromSystem(SystemConsts.SYS_NAME);
        remoteReq.setClientIp(req.getLoginIp());

        remoteReq.setAccount(req.getAccount());
        remoteReq.setPassword(req.getPassword());

        remoteReq.setLoginIp(req.getLoginIp());
        remoteReq.setDeviceId(req.getDeviceId());
        remoteReq.setDeviceType(req.getDeviceType());

        return remoteReq;
    }
}
